package com.kly.sc.api.application.aop;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.api.Response;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.StringUtils;
import com.google.common.collect.Lists;
import com.kly.dto.MemberDto;
import com.kly.dto.ReduceBenefitsDto;
import com.kly.enums.Benefits;
import com.kly.sc.api.application.annos.UserBenefitControl;
import com.kly.sc.api.application.constant.ApiRedisKeys;
import com.kly.sc.api.application.controller.im.request.ReceiveMessageRequest;
import com.kly.sc.api.application.controller.user.request.DoUserLikeRequest;
import com.kly.sc.api.application.enums.ApiResultStatus;
import com.kly.sc.api.application.enums.UserBehavior;
import com.kly.sc.api.application.service.user.HasMemberBenefitsValidationService;
import com.kly.sc.api.application.service.user.ScUserConversationService;
import com.kly.sc.api.application.service.utils.BaseComponent;
import com.kly.sc.api.application.service.utils.RedisService;
import com.kly.sc.api.application.vo.MemberBenefits;
import com.kly.sc.api.infras.exception.ApplicationException;
import com.kly.service.UserVasPurchasesService;
import com.kly.user.dto.UserConversationRecordDto;
import com.kly.user.dto.UserMsgDto;
import com.kly.user.enums.ConversationType;
import com.kly.user.enums.LikeEnum;
import com.kly.user.service.UserMsgService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.BiFunction;

@Aspect
@Component
public class UserAccessControlAop {

    private final Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    RedisClient redisClient;

    @Autowired
    RedisService redisService;

    @Resource
    BaseComponent baseComponent;

    @Resource
    UserMsgService userMsgService;

    @Autowired
    ScUserConversationService userConversationService;

    @Resource
    HasMemberBenefitsValidationService hasMemberBenefitsValidationService;
    @Resource
    UserVasPurchasesService userVasPurchasesService;
    /**
     * 离开会话
     */
    private static final Integer leaveChat = 2;

    private static final Integer ONE = 1;

    private static final Integer ZERO = 0;

    @Around("@annotation(userBenefitControl)")
    public Object handleLimitBrowseNumber(ProceedingJoinPoint pjp, UserBenefitControl userBenefitControl) throws Throwable {
        String userCode = baseComponent.getCurrentUserCode();
        MemberDto memberDto = baseComponent.retrieveMemberFromCacheOrService(userCode);
        boolean isMember = Optional.ofNullable(memberDto).isPresent();

        // 如果是会员用户则取消浏览量和like数量检查
        if (isMember) {
            return pjp.proceed();
        }

        UserBehavior userBehavior = UserBehavior.fromType(userBenefitControl.benefit());
        Object[] args = pjp.getArgs();

        Response response;

        switch (userBehavior) {
            case BROWSE:
                response = checkAndHandle(args, DoUserLikeRequest.class, this::handleBrowseAndLikeBehavior, userCode);
                break;

            case CONVERSATIONS:
                response = checkAndHandle(args, ReceiveMessageRequest.class, this::handleConversationsBehavior, userCode);
                break;

            default:
                throw new ApplicationException(ApiResultStatus.INCORRECT_VERIFICATION_LABEL);
        }

        if (!response.isSuccess()) {
            return response;
        }

        return pjp.proceed();
    }

    private <T> Response checkAndHandle(Object[] args, Class<T> clazz, BiFunction<T, String, Response> function, String userCode) {
        for (Object arg : args) {
            if (clazz.isInstance(arg)) {
                Response response = function.apply(clazz.cast(arg), userCode);
                if (response != null && !response.isSuccess()) {
                    return response;
                }
            }
        }
        return Response.ok();
    }

    /**
     * 处理浏览和喜欢的行为
     *
     * @param request  DoUserLikeRequest 对象
     * @param userCode 用户编码
     */
    private Response handleBrowseAndLikeBehavior(DoUserLikeRequest request, String userCode) {

            // 获取是否具备浏览与喜欢权限
            final List<MemberBenefits> memberBenefits = getMemberBenefits(request, userCode);
            // 是否具备权益判断
            for (MemberBenefits benefits : memberBenefits) {
                if (Objects.nonNull(benefits) && !benefits.getHasBenefits()) {
                    if (Benefits.NUMBER_OF_USERS_BROWSED.equals(benefits.getBenefitsType())) {
                        throw new ApplicationException(ApiResultStatus.USER_BROWSE_LIMIT);
                    } else if (Benefits.NUMBER_OF_USERS_LIKED.equals(benefits.getBenefitsType())) {
                        throw new ApplicationException(ApiResultStatus.USER_LIKE_LIMIT);
                    }
                }
            }

            // 浏览次数扣减
            ReduceBenefitsDto broseReduceBenefits = new ReduceBenefitsDto();
            broseReduceBenefits.setUserCode(userCode);
            broseReduceBenefits.setBenefitCode(Benefits.NUMBER_OF_USERS_BROWSED.getBenefitCode());
            final Response<String> broseResponse = userVasPurchasesService.reduceUserBenefits(broseReduceBenefits);
            logger.info("==== homepagePass, userCode:{}, toUserCode:{} reduceBenefitsResult:{}", userCode, request.getUserCodeFriend(), JSONObject.toJSONString(broseResponse));

            // 浏览次数扣减
            if (LikeEnum.LIKE.getType() == request.getLikeType()) {
                ReduceBenefitsDto likeReduceBenefits = new ReduceBenefitsDto();
                likeReduceBenefits.setUserCode(userCode);
                likeReduceBenefits.setBenefitCode(Benefits.NUMBER_OF_USERS_LIKED.getBenefitCode());
                final Response<String> likeResponse = userVasPurchasesService.reduceUserBenefits(likeReduceBenefits);
                logger.info("==== homepageLike, userCode:{}, toUserCode:{} reduceBenefitsResult:{}", userCode, request.getUserCodeFriend(), JSONObject.toJSONString(likeResponse));
            }

            return Response.ok();

    }

    private List<MemberBenefits> getMemberBenefits(DoUserLikeRequest request, String userCode) {
        List<Benefits> browseAndLikePermission = Lists.newArrayList();
        browseAndLikePermission.add(Benefits.NUMBER_OF_USERS_BROWSED);
        browseAndLikePermission.add(Benefits.NUMBER_OF_USERS_LIKED);
        final List<MemberBenefits> memberBenefits = hasMemberBenefitsValidationService.hasBenefits(browseAndLikePermission, userCode);
        logger.info("homepageBrowseBenefits, userCode:{}, request:{}, memberBenefits:{}", userCode, JSONObject.toJSONString(request), JSONUtil.toJsonPrettyStr(memberBenefits));
        if (CollectionUtils.isEmpty(memberBenefits)) {
            throw new ApplicationException(ApiResultStatus.USER_BROWSE_LIMIT);
        }
        return memberBenefits;
    }

    /**
     * 处理会话的行为
     *
     * @param request  ReceiveMessageRequest 对象
     * @param userCode 用户编码
     */
    private Response handleConversationsBehavior(ReceiveMessageRequest request, String userCode) {
        if (StringUtils.isEmpty(request.getToUserId())) {
            return Response.error(ApiResultStatus.USERID_CANNOT_BE_EMPTY);
        }
        if (Objects.nonNull(request.getType()) && request.getType().equals(leaveChat)) {
            return Response.ok();
        }

        // 会话数量校验
        final Integer remainSendMessageNum = hasMemberBenefitsValidationService.getRemainSendMessageNum(userCode, request.getToUserId());

        if (remainSendMessageNum < 1) {
            logger.error("The number of message has reached the upper limit, userCode:{}, toUserCode:{}", userCode, request.getToUserId());
            throw new ApplicationException("The number of message has reached the upper limit");
        }
        return Response.ok();
    }

    private List<MemberBenefits> getMemberBenefits(ReceiveMessageRequest request, String userCode) {
        List<Benefits> conversationPermissions = Lists.newArrayList();
        conversationPermissions.add(Benefits.ICE_BREAKING_SESSION);
        conversationPermissions.add(Benefits.EFFECTIVE_SESSION);
        conversationPermissions.add(Benefits.DEEP_SESSION);
        final List<MemberBenefits> memberBenefits = hasMemberBenefitsValidationService.hasBenefits(conversationPermissions, userCode);
        logger.info("conversationBenefits, userCode:{}, request:{}, memberBenefits:{}", userCode, JSONObject.toJSONString(request), JSONUtil.toJsonPrettyStr(memberBenefits));
        return memberBenefits;
    }


}